#include "File.h"

File::File(string fileName, int chunks){
    DBG_PRINTF(("creating %s with %i chunks\n", fileName.c_str(), chunks));
    _fileName = fileName;
    _chunks = chunks;
    _localChunks = 0;
    _chunkStatus = new bool[chunks];
    _copiesOnSystem = new int[chunks];
    for(int i = 0; i< chunks; i++){
        _chunkStatus[i] = false;
        _copiesOnSystem[i] = 0;
    }
}

File::~File(){
    delete _chunkStatus;
    delete _copiesOnSystem;
    // new destructor [*]
    /*
    delete _host;
    */
}



// accessors
string File::fileName(){
    return _fileName;
}

int File::chunks(){
    return _chunks;
}

bool File::isChunkPresent(int chunk){
    if(chunk <= _chunks){
        return _chunkStatus[chunk-1];
    }
    return false;
}

int File::localChunks() {
    int sum = 0;
    for (int i = 1; i <= _chunks; i++) {
        if ( isChunkPresent(i) ) {
            sum++;
        }
    }
    return sum;
}

int File::systemChunks(){
    int sum = 0;
    for(int i = 0; i< _chunks; i++){
        sum +=_copiesOnSystem[i];
    }
    return sum;
}

int File::fileReplicationLevel(){
    // = total number of chunks of this file in system / total number of chunks of this file
    return systemChunks() / _chunks;
}

int File::minimumChunkReplicationLevel(){
    // only considers chunk that is present on local peer
    int level = _copiesOnSystem[0];
    for(int i = 1; i< _chunks; i++){
        if(_copiesOnSystem[i] < level && _chunkStatus[i]){
            level = _copiesOnSystem[i];
        }
    }
    return level;
}

int File::leastReplicatedChunk(){
    // returns chunk 1 if all the same
    // only return chunk that is present on local peer
    int level = _copiesOnSystem[0];
    int leastChunk = 1;
    for(int i = 1; i< _chunks; i++){
        if(_copiesOnSystem[i] < level && _chunkStatus[i]){
            level = _copiesOnSystem[i];
            leastChunk = i + 1;
        }
    }
    return leastChunk;
}

int File::chunkReplicationLevel(int chunk){
    return _copiesOnSystem[chunk-1];
}

// used to update
int File::receivedChunk(int chunk){
    int status = SAFE;
    if(chunk <= _chunks){
        if(!_chunkStatus[chunk-1]){
            _copiesOnSystem[chunk-1]++;
            _chunkStatus[chunk-1] = true;
            _localChunks++;
        }
    }else{
        status = errChunkNotFound;
    }
    return status;
}

int File::successTransfer(int chunk){
    int status = SAFE;
    if(chunk <= _chunks){
        _copiesOnSystem[chunk-1]++;
    }else{
        status = errChunkNotFound;
    }
    return status;

}

int File::decreaseSystemChunk(int chunk) {
    int status = SAFE;
    if(chunk <= _chunks){
        _copiesOnSystem[chunk-1]--;
    }else{
        status = errChunkNotFound;
    }
    return status;
}

int File::completeFile(){
    _localChunks = _chunks;
    for(int i = 0; i< _chunks; i++){
        if(!_chunkStatus[i]){
            _copiesOnSystem[i]++;
            _chunkStatus[i] = true;
        }
    }
    return SAFE;
}

bool File::isComplete(){
    return _localChunks == _chunks;
}

int File::revertToLocalData(){
    for(int i = 0; i< _chunks; i++){
        if(_chunkStatus[i]){
            _copiesOnSystem[i] = 1;
        }else{
            _copiesOnSystem[i] = 0; 
        }           
    }
    return SAFE;
}

bool File::hasAnyChunk(){
    return _localChunks > 0;
}



// new things
File::File(string fileName, Host host, bool isLocalHosting, int versions){
    DBG_PRINTF(("creating %s with host ip %s and port %i\n", fileName.c_str(), host.ip(), host.port()));
    _fileName = fileName;
    _host = new Host(host.ip(), host.port());
    _isLocalHosting = isLocalHosting;
    _modified = false;
    _versions = versions;
    _isVersionPresentLocally.clear();
    _currentRevisions.clear();
    _status.clear();
    _needsUpdate.clear();
    for(int i = 0; i < versions; i++){
        _isVersionPresentLocally.push_back(false);
        _currentRevisions.push_back(0);
        _status.push_back(closed);
        _needsUpdate.push_back(unknown);
    }
}

int File::receivedLocalVersion(int versionNum, int revisionNum){
    int status = SAFE;
    if(versionNum >= _versions){
        _isVersionPresentLocally[versionNum-1] = true;
        _currentRevisions[versionNum-1] = revisionNum;
    }else{
        status = errVersionNotFound;
    }
    return status;
}   

// call this after saving the appropriate files on disk
int File::addHostingInformation(int versions, vector<int> currentRevisions, int totalRevisions){
    _versions = versions;
    _currentRevisions.clear();
    _totalRevisions = totalRevisions;
    for(int i = 0; i < versions; i++){
        _currentRevisions.push_back(currentRevisions[i]);
    }
    return SAFE;
}


int File::setFileStatus(int versionNum, Status newStatus){
    int status = SAFE;
    if(versionNum <= _versions){
        _status[versionNum-1] = newStatus;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::modifyFile(int versionNum){
    int status = SAFE;
    if(versionNum <= _versions){ 
        if (_status[versionNum-1] == opened ){
            _modified = true;
        }else{
            status = warnFileNotOpen;
        }
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::setVersionAvailability(bool availabilityOnNetwork){
    _isFileAvailableOnNetwork = availabilityOnNetwork;
    return SAFE;
}


bool File::isAvailable(int VersionNum){
    bool result = _isFileAvailableOnNetwork;
    if(!result){
        result = _isVersionPresentLocally[VersionNum-1];
    }
    return result;
}

